﻿using Microsoft.Xna.Framework;
using System;

namespace SceneManager.Components
{
	[RequireComponent(typeof(OccupiesSpaceComponent))]
	public class PhysicsComponent : Component
	{
		#region Events

		/// <summary>
		/// This can be used to update collision detection.
		/// </summary>
		public event EventHandler<EventArgs> OnUpdate;

		#endregion

		#region Variables

		private OccupiesSpaceComponent _occupiesSpace;

		private float _mass;
		private Vector2 _velocity;
		private bool _isAffectedByGravity;

		#endregion

		#region Constructors

		public PhysicsComponent(ComponentCollection parent)
			: base(parent)
		{
			_occupiesSpace = parent.Find<OccupiesSpaceComponent>();

			_mass = 1.0f;
			_velocity = Vector2.Zero;
			_isAffectedByGravity = false;
		}

		#endregion

		#region Properties

		public float Mass
		{
			get
			{
				return _mass;
			}
			private set
			{
				if (_mass != value)
				{
					_mass = value;
					PropertyHasChanged("Mass");
				}
			}
		}

		public Vector2 Velocity
		{
			get
			{
				return _velocity;
			}
			private set
			{
				if (_velocity != value)
				{
					_velocity = value;
					PropertyHasChanged("Velocity");
				}
			}
		}

		public Vector2 Momentum
		{
			get
			{
				return _velocity * _mass;
			}
		}

		public bool IsAffectedByGravity
		{
			get
			{
				return _isAffectedByGravity;
			}
			private set
			{
				if (_isAffectedByGravity != value)
				{
					_isAffectedByGravity = value;
					PropertyHasChanged("IsAffectedByGravity");
				}
			}
		}

		#endregion

		#region Methods

		public void ApplyImpulse(Vector2 impulse)
		{
			Velocity += impulse;
		}

		public void Stop()
		{
			Velocity = Vector2.Zero;
		}

		public override void Update(GameTime gameTime)
		{
			var oldPosition = _occupiesSpace.Position;
			_occupiesSpace.MoveBy(Velocity);
			var newPosition = _occupiesSpace.Position;
			var direction = newPosition - oldPosition;
			if (direction != Vector2.Zero)
			{
				_occupiesSpace.Rotation = (float)Math.Atan2(direction.Y, direction.X);
			}

			if (_isAffectedByGravity)
			{
				Scene.ApplyGravity(GameObject);
			}

			if (OnUpdate != null)
			{
				OnUpdate(this, EventArgs.Empty);
			}
		}

		#endregion
	}
}